﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MultiViewer.Network;
using System.Threading;
using MultiViewer.Display;
using System.Diagnostics;
using MouseSpace;
using MouseKeyboardLibrary;

namespace MultiViewer.Client
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow : MultiViewerWindow
    {
        private MouseWindow window;
        public MouseWindow Window
        {
            get { return this.window; }
            set { this.window = value; }
        }
        private bool cursor;
        public bool MousePressOn
        {
            get { return this.cursor; }
            set { this.cursor = value; }
        }
        private TraceViewer traceViewer;

        public MainWindow()
        {
            InitializeComponent();
            window = new MouseWindow();
            window.Visibility = Visibility.Hidden;
            traceViewer = new TraceViewer();
            Content = traceViewer;
#if DEBUG
            Trace.Listeners.Add(traceViewer.Listener);
#else
            Debug.Listeners.Add(traceViewer.Listener);
#endif
            Trace.WriteLine("MultiViewer.Client is starting...");
            Debug.WriteLine("MultiViewer is built in Debug mode");
        }

        protected override void OnClosed(EventArgs e)
        {
            if (Node != null)
                Node.Stop();
            base.OnClosed(e);
        }

        protected override void OnNodeConnected()
        {
            base.OnNodeConnected();
            Node.AddMessageHandler<InitDisplayRequest>(InitDisplayAsyncHandler);
            Node.AddMessageHandler<ShutdownRequest>(ShutdownAsyncHandler);
            Node.AddNotificationHandler<MouseNotification>(MouseNotificationHandler);
            Node.AddNotificationHandler<MouseClickNotification>(MouseClickNotificationHandler);
        }

        private object Invoke<T>(MessageHandler<T> handler, T argument)
        {
            object result = null;
            Dispatcher.Invoke(new SyncInvoker(delegate()
            {
                try
                {
                    result = handler(argument);
                }
                catch (Exception exc)
                {
                    Trace.WriteLine("Exception in " + typeof(T).Name + " handler: " + exc.Message);
                }
            }));
            return result;
        }

        private void BeginInvoke<T>(NotificationHandler<T> handler, T argument)
        {
            Dispatcher.BeginInvoke(new SyncInvoker(delegate()
            {
                try
                {
                    handler(argument);
                }
                catch (Exception exc)
                {
                    Trace.WriteLine("Exception in " + typeof(T).Name + " handler: " + exc.Message);
                }
            }));
        }

        private object InitDisplayAsyncHandler(InitDisplayRequest request)
        {
            return Invoke(InitDisplayHandler, request);
        }

        private object InitDisplayHandler(InitDisplayRequest request)
        {
            // TODO: Instead of MessageBox:
            // 1. Resize main window
            // 2. Replace Child object with content renderer
            MessageBox.Show(String.Format("InitDisplay: {0}x{1}x{2}", request.Width, request.Height, request.Fullscreen));
            this.Width = request.Width;
            this.Height = request.Height;
            this.window.Width = request.CursorWidth;
            this.window.Height = request.CursorHeight;
            this.MousePressOn= request.Cursor;
            return true;
        }

        private object ShutdownAsyncHandler(ShutdownRequest request)
        {
            return Invoke(ShutdownHandler, request);
        }

        private object ShutdownHandler(ShutdownRequest request)
        {
            Close();
            return true;
        }

        private void MouseNotificationAsyncHandler(MouseNotification e)
        {
            BeginInvoke(MouseNotificationHandler, e);
        }

        private void MouseNotificationHandler(MouseNotification e)
        {
            try
            {
                // TODO: handle mouse events properly
                if (!window.Dispatcher.CheckAccess())
                {
                    this.Dispatcher.Invoke(
                      System.Windows.Threading.DispatcherPriority.Normal,
                      new Action(
                        delegate()
                        {
                            if (e.X != -10000)
                            {
                                if(this.MousePressOn) MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                if (this.MousePressOn) MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                window.Visibility = Visibility.Visible;
                                window.Left = e.X + this.Left;
                                window.Top = e.Y + this.Top;
                                window.Show();
                            }
                            else
                            {
                                if (window != null) window.Visibility = Visibility.Hidden;
                            }
                        }
                    ));
                }
                else
                {
                    if (e.X != -10000)
                    {
                        window.Visibility = Visibility.Visible;
                        window.Left = e.X + this.Left;
                        window.Top = e.Y + this.Top;
                        window.Show();
                    }
                    else
                    {
                        if (window != null) window.Visibility = Visibility.Hidden;
                    }
                }
            }
            catch (Exception ex)
            {
                string temp = ex.Message;
            }
        }

        private void MouseCLickNotificationAsyncHandler(MouseClickNotification e)
        {
            BeginInvoke(MouseClickNotificationHandler, e);
        }

        private void MouseClickNotificationHandler(MouseClickNotification e)
        {
            try
            {
                if (!this.Dispatcher.CheckAccess())
                {
                    window.Dispatcher.Invoke(
                      System.Windows.Threading.DispatcherPriority.Normal,
                      new Action(
                        delegate()
                        {
                            if (e.Button == MultiViewer.Display.MouseButton.LeftDown)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Left);
                            }
                            else if (e.Button == MultiViewer.Display.MouseButton.LeftUp)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Left);
                            }
                            else if (e.Button == MultiViewer.Display.MouseButton.RightDown)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Right);
                            }
                            else if (e.Button == MultiViewer.Display.MouseButton.RightUp)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Right);
                            }
                        }
                                ));
                }
                else
                {
                    if (e.Button == MultiViewer.Display.MouseButton.LeftDown)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Left);
                    }
                    else if (e.Button == MultiViewer.Display.MouseButton.LeftUp)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Left);
                    }
                    else if (e.Button == MultiViewer.Display.MouseButton.RightDown)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Right);
                    }
                    else if (e.Button == MultiViewer.Display.MouseButton.RightUp)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Right);
                    }
                }

            }
            catch (Exception ex)
            {
                string temp = ex.Message;
            }
        }

        private void MultiViewerWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            window.Close();
        }
    }
}
